#ifndef __DRAW__
#define __DRAW__

#include "header.h"
#include "window.h"
#include "bool_interval.h"
#include "mymath.h"
#include "interval.h"
#include "domain_track_interval.h"
#include "formula_sytanmic.h"
#include <set>
class Formula;
namespace draw {
    inline int toInt(double x) {
        return (int)x;
    }
    template<class I_type>
    struct IntervalTwinsComparator {
        const bool operator()(const std::pair<I_type, I_type>&l, const std::pair<I_type, I_type>& r) const {
            return l.first.unsafeA() < r.first.unsafeA() ||
                    (l.first.unsafeA() == r.first.unsafeA() && l.second.unsafeA() < r.second.unsafeA());
        }
    };  // set的比较器, 按照区域的x坐标由小到大自动排序, 一个pair是一个区域
}

template<class INV>
class Draw : public Window {
public:
    using I_type = INV;
    using U_type = std::set<std::pair<I_type, I_type>, draw::IntervalTwinsComparator<I_type>>;

    int compare_ = 0;

    DTInterval gfx(DTInterval x) {
        return x;
    }
    BoolInterval gfyg(Formula lfo, Formula rfo, DTInterval fx, DTInterval y) {
        return lfo.calresult(fx, y) > rfo.calresult(fx, y);
    }
    BoolInterval gfyl(Formula lfo, Formula rfo, DTInterval fx, DTInterval y) {
        return lfo.calresult(fx, y) < rfo.calresult(fx, y);
    }

    void SetPenColor4Sloutions() const {
        SDL_SetRenderDrawColor(renderer_, 255, 0, 0, 255);
    }
    void SetPenColor4nonSloution() const {
        SDL_SetRenderDrawColor(renderer_, 255, 255, 255, 255);
    }
    void SetPenColor4Undefined() const {
        SDL_SetRenderDrawColor(renderer_, 127, 127, 127, 255);
    }

    Draw(double L, double R, double B, double T) :
        L_(L), R_(R), B_(B), T_(T),
        U_({}), U1_({}), k_(0) {
        renderer_ = SDL_CreateRenderer(Window::GetWindow(),-1, SDL_RENDERER_ACCELERATED);
        SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND);
        grid_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, Window::GetWidth(), Window::GetHeight());
        graph_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, Window::GetWidth(), Window::GetHeight());
        fontex_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, Window::GetWidth(), Window::GetHeight());
        SDL_SetTextureBlendMode(grid_, SDL_BLENDMODE_BLEND);
        SDL_SetTextureBlendMode(graph_, SDL_BLENDMODE_BLEND);
        SDL_SetTextureBlendMode(fontex_, SDL_BLENDMODE_BLEND);

        SetStartStatus();
    }

    ~Draw() {
        SDL_DestroyTexture(grid_);
        grid_ = nullptr;
        SDL_DestroyTexture(graph_);
        graph_ = nullptr;
        SDL_DestroyRenderer(renderer_);
        renderer_ = nullptr;
    }

    void SetStartStatus() {
        U_.clear();
        U1_.clear();
        // 初始纹理为透明
        SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
        SDL_SetRenderTarget(renderer_, grid_);
        SDL_RenderClear(renderer_);
        SDL_SetRenderTarget(renderer_, graph_);
        SDL_RenderClear(renderer_);
        SDL_SetRenderTarget(renderer_, fontex_);
        SDL_RenderClear(renderer_);
        SDL_SetRenderTarget(renderer_, nullptr);

        // initialize
        k_ = mygcd(Window::GetWidth(), Window::GetHeight());
        k_ = (int)(log2(mygcd(k_, 1 << (int)(log2(k_)))));

        int k2 = 1 << k_;   // 2^k
        // 以上几步是为了将图像绘制在wh所能决定的最大正方形内
        // 并且这个正方形能被无限四等份
        for (int a = 0; a < Window::GetWidth(); a += k2)
        for (int b = 0; b < Window::GetHeight(); b += k2)
            U_.insert(
                std::pair<I_type, I_type>(
                    intervalFromReals<I_type>(a, a+k2),
                    intervalFromReals<I_type>(b, b+k2)) );  // 区域会按照x从小到大排好
    }

    void Setflrfo(Formula lfo, Formula rfo) {
        lfo_ = lfo;
        rfo_ = rfo;
    }

    void finish()  {
        while (k_ >= 0 && !U_.empty()) {
            step();
        }
        // 绘制坐标系
        SDL_SetRenderTarget(renderer_, graph_);
        drawCardinate();
        SDL_SetRenderTarget(renderer_, grid_);
        drawCardinate();
    }

    // 画网格线的
    // 绘制当前的格子
    void drawCurGrid() {
        SDL_SetRenderDrawColor(renderer_, 0, 0, 200, 255);  //格子线的颜色
        for (const std::pair<I_type, I_type>& p : U_) {
            SDL_Rect urect = regionToRect(p.first, p.second);
            SDL_RenderDrawRect(renderer_, &urect);
        }
    }

    void step() {
        --k_;
        // 只有两步, --k和RefinePixels(r, U_)
        std::cout << "U_len: " << U_.size() << ", " << "U1_len: " << U1_.size() << std::endl;

        // RefinePixels开始
        // set的好处, 清除集合内容[U1_是U_(k-1)]
        U1_.clear();

        bool firstRun = true;
        double lastX = -1;
        I_type fx = intervalFromReals<I_type>(0, 0);
        for (const std::pair<I_type, I_type>& p : U_) {
            const I_type& a = p.first;
            const I_type& b = p.second;

            // 第一次运行更新lastX
            if (lastX != a.unsafeA() || firstRun) {
                firstRun = false;

                lastX = a.unsafeA();
                fx = gfx(pixelToRealH(a));
            }

            BoolInterval r(false, false);
            if (compare_ == 0) {
                r = gfyg(lfo_, rfo_, fx, pixelToRealV(b));
            }
            else {
                r = gfyl(lfo_, rfo_, fx, pixelToRealV(b));
            }

            if (r.a()) // (T, T)
                SetPenColor4Sloutions();  // 因为F<T, 区间(F, T)和(T, F)应该都会变成(F, T), 所以只有(F, T), (F, F)和(T, T)
            else if (!r.b())  // (F, F)
                SetPenColor4nonSloution();
            else {  // (F, T)
                SetPenColor4Undefined();

                double midXL = divDown(addDown(a.unsafeA(), a.unsafeB()), 2);
                double midXR = divUp(addUp(a.unsafeA(), a.unsafeB()), 2);

                double midYB = divDown(addDown(b.unsafeA(), b.unsafeB()), 2);
                double midYT = divUp(addUp(b.unsafeA(), b.unsafeB()), 2);

                // 1  2
                // 3  4
                U1_.insert(// 3
                    std::pair<I_type, I_type>(
                        intervalFromReals<I_type>(a.unsafeA(), midXR),
                        intervalFromReals<I_type>(b.unsafeA(), midYT)
                    )
                );
                U1_.insert(// 4
                    std::pair<I_type, I_type>(
                        intervalFromReals<I_type>(midXL, a.unsafeB()),
                        intervalFromReals<I_type>(b.unsafeA(), midYT)
                    )
                );
                U1_.insert(// 1
                    std::pair<I_type, I_type>(
                        intervalFromReals<I_type>(a.unsafeA(), midXR),
                        intervalFromReals<I_type>(midYB, b.unsafeB())
                        )
                );
                U1_.insert(// 2
                    std::pair<I_type, I_type>(
                        intervalFromReals<I_type>(midXL, a.unsafeB()),
                        intervalFromReals<I_type>(midYB, b.unsafeB())
                    )
                );
            }

            SDL_Rect urect = regionToRect(a, b);
            SDL_RenderFillRect(renderer_, &urect);
            // std::cout << "x: " << urect.x << std::endl;
            // std::cout << "y: " << urect.y << std::endl;
            // std::cout << "w: " << urect.w << std::endl;
            // std::cout << "h: " << urect.h  << std::endl;
        }

        std::cout << "pre_swp --> U_len: " << U_.size() << ", " << "U1_len: " << U1_.size() << std::endl;
        std::swap(U_, U1_);
        std::cout << "pre_swp --> U_len: " << U_.size() << ", " << "U1_len: " << U1_.size() << std::endl;
    }

    I_type pixelToRealH(I_type x) const {
      return intervalFromReals<I_type>(pixelToRealL(x.unsafeA()), pixelToRealR(x.unsafeB()));
    }
    I_type pixelToRealV(I_type x) const {  // V = Verify？
      return intervalFromReals<I_type>(pixelToRealB(x.unsafeA()), pixelToRealT(x.unsafeB()));
    }

    void drawCardinate() {
        SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 255);  //格子线的颜色
        SDL_RenderFillRect(renderer_, &rectx_);
        SDL_RenderFillRect(renderer_, &recty_);
    }
    SDL_Renderer* GetRenderer() const {return renderer_;}
    SDL_Texture* GetGrid() const {return grid_;}
    SDL_Texture* GetGraph() const {return graph_;}
    SDL_Texture* GetFontgraph() const {return fontex_;}

private:
    SDL_Renderer* renderer_;
    SDL_Texture* grid_;
    SDL_Texture* graph_;
    SDL_Texture* fontex_;  // equal formule
    Formula lfo_;
    Formula rfo_;
    double L_, R_, B_, T_;
    U_type U_, U1_;
    int k_;  // 利用WH的gcd得到最大的正方形绘图区域

    SDL_Rect rectx_ = {0, Window::GetHeight()/2 - 4, Window::GetWidth(), 8};
    SDL_Rect recty_ = {Window::GetWidth()/2 - 6, 0, 8, Window::GetHeight()};

    double pixelToRealL(double x) const {
        return addDown(
            L_,
            divDown( subDown(mulDown(x, R_), mulUp(x, L_)),
                    (double)(Window::GetWidth()) )
        );
    }

    double pixelToRealR(double x) const {
        return addUp(
                L_,
                divUp(subUp(mulUp(x, R_), mulDown(x, L_)),
                    (double)(Window::GetWidth()) )
        );
    }

    double pixelToRealB(double y) const {
        return addDown(
            B_,
            divDown(
                subDown(mulDown(y, T_), mulUp(y, B_)),
                (double)(Window::GetHeight()) )
        );
    }

    double pixelToRealT(double y) const {
        return addUp(
            B_,
            divUp(
                subUp(mulUp(y, T_), mulDown(y, B_)),
                (double)(Window::GetHeight()) )
        );
    }

    SDL_Rect regionToRect(I_type h, I_type v) {
        using draw::toInt;
        int rx = toInt(h.unsafeA());
        int ry = Window::GetHeight()- toInt(v.unsafeA());
        int rw = toInt(h.unsafeB()) - rx;
        int rh = Window::GetHeight()- toInt(v.unsafeB()) - ry;
        SDL_Rect rect = {rx, ry, rw, rh};
        return rect;
    }

    // const int Centerlizex = Window::GetWidth() / 2;
    // const int Centerlizey = Window::GetHeight() / 2;

};

#endif
